package com.xinzhidi.auth.controller;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import com.xinzhidi.auth.utils.MyStringUtil;
import com.xinzhidi.common.core.constant.CacheConstants;
import com.xinzhidi.common.core.domain.R;
import com.xinzhidi.common.core.exception.ServiceException;
import com.xinzhidi.common.core.utils.StringUtils;
import com.xinzhidi.common.core.web.domain.AjaxResult;
import com.xinzhidi.common.redis.service.RedisService;
import com.xinzhidi.system.api.domain.OpenIdDto;
import com.xinzhidi.system.api.model.OpenIdLoginBody;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpMessageRouter;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;


@Slf4j
@RestController
@RequestMapping(value = "/wechat")
public class WechatController {


    @Autowired
    private WxMpMessageRouter wxMpMessageRouter;


    @Autowired
    private WxMaService wxMaService;

    @Autowired
    private WxMpService wxMpService;

    @Value("${backUrl:}")
    private String backUrl;

    @Autowired
    private RedisService redisService;

    /**
     * 处理微信消息（未使用过）
     *
     * @return
     * @throws IOException
     */
    @PostMapping("/message")
    public String handleMessage(@RequestBody String requestBody, @RequestParam("signature") String signature,
                                @RequestParam(name = "encrypt_type", required = false) String encType,
                                @RequestParam(name = "msg_signature", required = false) String msgSignature,
                                @RequestParam("timestamp") String timestamp, @RequestParam("nonce") String nonce) {
        log.info(
                "\n接收微信请求：[signature=[{}], encType=[{}], msgSignature=[{}],"
                        + " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ",
                signature, encType, msgSignature, timestamp, nonce, requestBody);
        if (!wxMpService.checkSignature(timestamp, nonce, signature)) {
            throw new IllegalArgumentException("非法请求，可能属于伪造的请求！");
        }

        String out = null;
        if (encType == null) {
            WxMpXmlMessage inMessage = WxMpXmlMessage.fromXml(requestBody);
            WxMpXmlOutMessage outMessage = wxMpMessageRouter.route(inMessage);
            if (outMessage == null) {
                return "";
            }
            out = outMessage.toXml();
        } else if ("aes".equals(encType)) {
            // aes加密的消息
            WxMpXmlMessage inMessage = WxMpXmlMessage.fromEncryptedXml(requestBody,
                    wxMpService.getWxMpConfigStorage(), timestamp, nonce, msgSignature);
            log.debug("\n消息解密后内容为：\n{} ", inMessage.toString());
            WxMpXmlOutMessage outMessage = wxMpMessageRouter.route(inMessage);
            if (outMessage == null) {
                return "";
            }

            out = outMessage.toEncryptedXml(wxMpService.getWxMpConfigStorage());
        }

        log.debug("\n组装回复信息：{}", out);

        return out;
    }

    /**
     * 授权 （未使用过）
     *
     * @param signature
     * @param timestamp
     * @param nonce
     * @param echostr
     * @return
     */
    @GetMapping("/message")
    public String authGet(@RequestParam(name = "signature", required = false) String signature,
                          @RequestParam(name = "timestamp", required = false) String timestamp,
                          @RequestParam(name = "nonce", required = false) String nonce,
                          @RequestParam(name = "echostr", required = false) String echostr) {
        log.info("\n接收到来自微信服务器的认证消息：[{}, {}, {}, {}]", signature, timestamp, nonce, echostr);
        if (StringUtils.isAnyBlank(signature, timestamp, nonce, echostr)) {
            throw new IllegalArgumentException("请求参数非法，请核实!");
        }
        if (wxMpService.checkSignature(timestamp, nonce, signature)) {
            return echostr;
        }

        return "非法请求";
    }

    /**
     * 公众号-获取登录二维码 （url格式的二维码）
     *
     * @return 登录二维码
     */
    @GetMapping("/getQrCode")
    public R<Map> getQrCode() {
        //本次生成二维码的唯一标识，前端通过轮询访问getScanCodeConfirmationResult接口传入sceneStr参数确认是否已经扫码
        String sceneStr = MyStringUtil.getRandomString(8);
        log.info("登录二维码：{}",sceneStr);
        try {
            WxMpQrCodeTicket wxMpQrCodeTicket = wxMpService.getQrcodeService().qrCodeCreateTmpTicket(sceneStr, 60 * 5);
            Map<String, String> map = new HashMap<>();
            map.put("qrCodeUrl", wxMpService.getQrcodeService().qrCodePictureUrl(wxMpQrCodeTicket.getTicket()));
            map.put("sceneStr", sceneStr);
            return R.ok(map);
        } catch (Exception e) {
            e.printStackTrace();
            return R.fail();
        }
    }

    /**
     * 公众号- （获取微信code）
     *
     * @return 获取微信code
     */
    @GetMapping("/getLoginQrCode")
    public R<String> getLoginQrCode() {
        String sceneStr = MyStringUtil.getRandomString(8);
        log.info("getLoginQrCode：{}",sceneStr);
        try {
            String s = wxMpService.getOAuth2Service().buildAuthorizationUrl(backUrl+ "/dev-api/auth/saomaLogin", WxConsts.OAuth2Scope.SNSAPI_USERINFO, null);
            return R.ok(s);
        } catch (Exception e) {
            e.printStackTrace();
            return R.fail();
        }
    }

    /**
     *  确认二维码接口 扫码确认（确认后会将token信息放入redis，在getScanCodeConfirmationResult接口返回token）
     *
     * @return 确认二维码接口
     */
    @GetMapping("/makesureInfo")
    public AjaxResult makesureInfo( HttpServletRequest req) throws IOException {
        String msg;
        int returnCode = 200;
        //菜单按钮的回调code 用于获取用户的openid
        String code = req.getParameter("code");
        String param = req.getParameter("param");
        log.info("接收到微信请求code：{}，param：{}",code,param);

        WxMaJscode2SessionResult user = null;
        try {
            user = this.wxMaService.jsCode2SessionInfo(code);
            log.info("接收到微信用户user：{}",user.toString());
            if (StringUtils.isEmpty(user.getOpenid())){
                throw new ServiceException("未找到用户");
            }
            OpenIdLoginBody form = new OpenIdLoginBody();
            form.setOpenId(user.getOpenid());
//            确认数据库用户信息是否存在，增加自己的判断逻辑
//            userInfo = openIdLogin(form);
//            if (ObjectUtils.isEmpty(userInfo)){
//                return new AjaxResult(500, "未绑定系统用户");
//            }
        } catch (WxErrorException e) {
            e.printStackTrace();
            throw new ServiceException("微信登录失败");
        }

        msg = "操作成功";
        return new AjaxResult(returnCode, msg);
    }

    /** ,
     *
     * 前端用户轮询获取扫码用户信息，返回token信息，前端判断返回用户信息后调用登录之后的逻辑
     *
     * @param scene
     * @return
     */
    @RequestMapping("/getScanCodeConfirmationResult")
    public R getScanCodeConfirmationResult(@RequestParam String scene) {
        String cacheKey = getCacheKey(scene);
        if (Boolean.FALSE.equals(redisService.hasKey(cacheKey))) {
            return R.ok("等待用户扫码");
        }
        Boolean cacheObject = redisService.getCacheObject(cacheKey);
        redisService.deleteObject(scene);
        return R.ok(cacheObject);
    }

    /**
     * （弃用）
     * @param req
     * @param response
     * @return
     * @throws Exception
     */
    @PostMapping("/wxconnect")
    public @ResponseBody String weixinConnect(HttpServletRequest req, HttpServletResponse response) throws Exception {
        // 如果是微信发过来的GET请求
        System.out.println("微信连接成功！");
        return req.getParameter("echostr");
    }

    /**
     * 编辑二维码 微信小程序绑定/更新用户
     */
    @GetMapping("/updateOpenId")
    public AjaxResult updateOpenId(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        String msg = "";
        String returnCode = "";
        try {
            //菜单按钮的回调code 用于获取用户的openid
            String code = req.getParameter("code");
            //param暂定的‘updateOpenId--id’
            String param = req.getParameter("param");
            log.info("接收到微信请求code：{}，param：{}",code,param);

            //获取openid
            String openid = "";

            //公众号绑定
//            WxOAuth2AccessToken accessToken = this.wxMpService.getOAuth2Service().getAccessToken(code);
            //小程序绑定
            WxMaJscode2SessionResult user = this.wxMaService.jsCode2SessionInfo(code);
            openid = user.getOpenid();

            log.info("接收到微信用户user：{}",user.toString());
            if (StringUtils.isEmpty(openid)){
                returnCode = "500";
                msg = "未找到用户";
            } else{
                OpenIdDto openIdDto=new OpenIdDto();
                openIdDto.setId(Integer.parseInt(param.split("--")[1]));
                openIdDto.setOpenId(openid);
                log.info("id:{}",openIdDto.getId());
                log.info("openid:{}",openIdDto.getOpenId());
                //更新openid方法
//                R r = remoteUserService.updateOpenId(openIdDto, SecurityConstants.INNER);
//                log.info("扫码更新返回：{}",JSONObject.toJSONString(r));
//                returnCode = String.valueOf(r.getCode());
//                msg = r.getMsg();
            }
            log.info("扫码确认返回,returnCode:{},msg:{}",returnCode,msg);
        } catch (Exception e) {
            e.printStackTrace();
            returnCode = String.valueOf(R.fail());
            msg = e.getMessage();
        }
        if (StringUtils.isEmpty(msg)){
            msg = "操作成功";
        }

        //小程序绑定
        return new AjaxResult(Integer.parseInt(returnCode), msg, null);
        //公众号绑定
//        resp.sendRedirect(backUrl+"/bweb/phoneMessageless.html?code="+returnCode+"&msg="+ URLEncoder.encode(msg));
    }


    /**
     * 设置cache key
     *
     * @param configKey 参数键
     * @return 缓存键key
     */
    private String getCacheKey(String configKey)
    {
        return CacheConstants.SCAN_CODE_CONFIRMATION_KEY + configKey;
    }

}
